#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    g-octave
    ~~~~~~~~
    
    Main script of g-Octave.
    
    :copyright: (c) 2009-2010 by Rafael Goncalves Martins
    :license: GPL-2, see LICENSE for more details.
"""

__issue_tracker = 'http://g-octave.rafaelmartins.eng.br/report'

import sys

# This block ensures that ^C interrupts are handled quietly.
# Code snippet from Portage
try:
    import signal

    def exithandler(signum,frame):
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        signal.signal(signal.SIGTERM, signal.SIG_IGN)
        sys.exit(1)

    signal.signal(signal.SIGINT, exithandler)
    signal.signal(signal.SIGTERM, exithandler)

except KeyboardInterrupt:
    sys.exit(1)


import os
import optparse
import portage
import subprocess

out = portage.output.EOutput()

current_dir = os.path.dirname(os.path.realpath(__file__))
if os.path.exists(os.path.join(current_dir, '..', 'g_octave')):
    sys.path.insert(0, os.path.join(current_dir, '..'))

import g_octave

def main():

    parser = optparse.OptionParser(
        usage = '%prog [options] <package_name | package_name-version>',
        version = '%prog ' + g_octave.__version__,
        description = g_octave.__description__
    )
    
    parser.add_option(
        '-l', '--list',
        action = 'store_true',
        dest = 'list',
        default = False,
        help = 'show a list of packages available to install and exit'
    )
    
    parser.add_option(
        '-i', '--info',
        action = 'store_true',
        dest = 'info',
        default = False,
        help = 'show a description of the required package and exit'
    )
    
    parser.add_option(
        '-p', '--pretend',
        action = 'store_true',
        dest = 'pretend',
        default = False,
        help = 'don\'t (un)merge packages, only create ebuilds and solve the dependencies'
    )
    
    parser.add_option(
        '-a', '--ask',
        action = 'store_true',
        dest = 'ask',
        default = False,
        help = 'ask to confirmation before perform (un)merges'
    )
    
    parser.add_option(
        '-v', '--verbose',
        action = 'store_true',
        dest = 'verbose',
        default = False,
        help = 'Portage makes a lot of noise.'
    )
    
    parser.add_option(
        '-C', '--unmerge',
        action = 'store_true',
        dest = 'unmerge',
        default = False,
        help = 'try to unmerge a package instead of merge'
    )
    
    parser.add_option(
        '-f', '--force',
        action = 'store_true',
        dest = 'force',
        default = False,
        help = 'forces the recreation of the ebuilds'
    )
    
    parser.add_option(
        '--force-all',
        action = 'store_true',
        dest = 'force_all',
        default = False,
        help = 'forces the recreation of the overlay and of the ebuilds'
    )
    
    parser.add_option(
        '--no-colors',
        action = 'store_false',
        dest = 'colors',
        default = True,
        help = 'don\'t use colors on the CLI'
    )
    
    parser.add_option(
        '--sync',
        action = 'store_true',
        dest = 'sync',
        default = False,
        help = 'search for updates of the package database, patches and auxiliary files'
    )
    
    options, args = parser.parse_args()
    
    if not options.colors:
        portage.output.nocolor()
    
    from g_octave.config import Config
    from g_octave.fetch import need_update, check_updates, download_files, check_db_cache
    
    conf_prefetch = Config(True)
    
    # checking if our overlay is correctly added to PORTDIR_OVERLAY
    if conf_prefetch.overlay not in portage.settings['PORTDIR_OVERLAY'].split(' '):
        out.eerror('g-octave overlay is not configured!')
        out.eerror('You must append your overlay dir to PORTDIR_OVERLAY.')
        out.eerror('Overlay: %s' % conf_prefetch.overlay)
        return os.EX_CONFIG
    
    # checking if we have a package database
    if need_update() and not options.sync:
        out.eerror('Please run "g-octave --sync" to download a package database!')
        return os.EX_USAGE
    
    if options.sync:
        
        out.einfo('Searching updates ...')
        
        files = check_updates()
        
        if len(files) > 0:
            out.einfo('Updates are available. Downloading ...')
            print
            download_files(files)
            print
            out.einfo('Done.')
        else:
            out.einfo('No updates available.')
        
        return os.EX_OK
    
    check_db_cache()

    conf = Config()

    from g_octave.description import Description
    from g_octave.description_tree import DescriptionTree
    from g_octave.ebuild import Ebuild, EbuildException
    from g_octave.overlay import create_overlay

    if options.list:
        tree = DescriptionTree()
        print portage.output.blue('Available packages:\n')
        for category in tree.pkg_list:
            print portage.output.white('%s:') % category
            for pkg in tree.pkg_list[category]:
                print '\t%s-%s' % (pkg['name'], pkg['version'])
            print
        return os.EX_OK
    elif len(args) == 0:
        out.eerror('You need provide a package atom or "--list" or "--sync"')
        return os.EX_USAGE
    elif len(args) > 1:
        out.eerror('At this moment g-octave can install only one package at once')
        return os.EX_USAGE
    
    # if we're alive yet, we have a package to install! :D
    
    create_overlay(options.force_all)
    
    try:
        ebuild = Ebuild(args[0], options.force or options.force_all)
    except EbuildException:
        out.eerror('Package not found: %s' % args[0])
        return os.EX_DATAERR
    
    if options.info:
        pkg = ebuild.description()
        print portage.output.blue('Package:'), portage.output.white(str(pkg.name))
        print portage.output.blue('Version:'), portage.output.white(str(pkg.version))
        print portage.output.blue('Date:'), portage.output.white(str(pkg.date))
        print portage.output.blue('Maintainer:'), portage.output.white(str(pkg.maintainer))
        print portage.output.blue('Description:'), portage.output.white(str(pkg.description))
        print portage.output.blue('Categories:'), portage.output.white(str(pkg.categories))
        print portage.output.blue('License:'), portage.output.white(str(pkg.license))
        print portage.output.blue('Url:'), portage.output.white(str(pkg.url))
        return os.EX_OK
    
    atom = ebuild.create()
    
    emerge = ['emerge']
    options.ask and emerge.append('--ask')
    options.verbose and emerge.append('--verbose')
    options.pretend and emerge.append('--pretend')
    options.unmerge and emerge.append('--unmerge')
    if not options.colors:
        emerge.append('--color=n')
    emerge.append(atom)
    
    emerge_ret = subprocess.call(emerge)
    
    if emerge_ret != os.EX_OK:
        out.eerror('"emerge" returned an error.')
        sys.exit(emerge_ret)
    
    if options.unmerge:
        print
        out.einfo('You may want to remove the dependencies too, using:')
        out.einfo('# emerge -av --depclean')
    
    return os.EX_OK


if __name__ == '__main__':
    
    from g_octave.exception import *
    
    return_code = os.EX_OK
    
    try:
        return_code = main()
    except ConfigException, error:
        out.eerror('Config class error - %s' % error)
        return_code = os.EX_CONFIG
    except DescriptionException, error:
        out.eerror('Description class error - %s' % error)
        return_code = os.EX_SOFTWARE
    except DescriptionTreeException, error:
        out.eerror('DescriptionTree class error - %s' % error)
        return_code = os.EX_SOFTWARE
    except EbuildException, error:
        out.eerror('Ebuild class error - %s' % error)
        return_code = os.EX_SOFTWARE
    except FetchException, error:
        out.eerror('Fetch module error - %s' % error)
        return_code = os.EX_SOFTWARE
    except OSError, error:
        out.eerror('Operating System error - %s' % error)
        out.eerror('Try run "g-octave" as root.')
        return_code = os.EX_OSERR
    except IOError, error:
        out.eerror('I/O error - %s' % error)
        out.eerror('Try run "g-octave" as root.')
        return_code = os.EX_IOERR
    except KeyError, error:
        out.eerror('Key error - %s' % error)
        out.eerror('Probably you have more than one overlay configured to use with g-octave')
        out.eerror('Try remove the oldest and maintain only the overlay actually in use.')
        return_code = os.EX_SOFTWARE
    except Exception, error:
        out.eerror('Unknown error - %s' % error)
        return_code = os.EX_SOFTWARE
    
    if return_code not in [os.EX_OK, os.EX_CONFIG, os.EX_USAGE, os.EX_DATAERR]:
        out.einfo('If you fell that this is a bug, please report to us.')
        out.einfo('Issue tracker: %s' % __issue_tracker)
    
    sys.exit(return_code)
